﻿using System.Diagnostics;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

var logTest = LogTest.Activity;

// JsonFile config
if (logTest == LogTest.JsonConfig)
{
    var configuration = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("logging.json")
        .Build();
    var loggerFactory = new ServiceCollection()
        .AddLogging(builder => builder.AddConfiguration(configuration)
            .AddConsole()
            .AddDebug())
        .BuildServiceProvider()
        .GetRequiredService<ILoggerFactory>();

    Log(loggerFactory, "Foo");
    Log(loggerFactory, "Bar");
    Log(loggerFactory, "Baz");
    Console.ReadKey();

    static void Log(ILoggerFactory loggerFactory, string category)
    {
        var logger = loggerFactory.CreateLogger(category);
        var levels = (LogLevel[]) Enum.GetValues(typeof(LogLevel));
        levels = levels.Where(l => l != LogLevel.None).ToArray();
        var eventId = 1;
        Array.ForEach(levels, level => logger.Log(level, eventId++, $"this is a/an {level} log message"));
    }
}

// SimpleConsole
else if (logTest == LogTest.Simple)
{
    var logger = new ServiceCollection()
        .AddLogging(builder => builder
            .AddConsole()
            .AddSimpleConsole(options=> options.IncludeScopes = true))
        .BuildServiceProvider()
        .GetRequiredService<ILogger<Program>>();
    using (logger.BeginScope($"Foobar Transaction[{Guid.NewGuid()}]"))
    {
        var stopwatch = Stopwatch.StartNew();
        await Task.Delay(500);
        logger.LogInformation("Operation foo completes at {0}", stopwatch.Elapsed);

        await Task.Delay(300);
        logger.LogInformation("Operation bar completes at {0}", stopwatch.Elapsed);
        
        await Task.Delay(800);
        logger.LogInformation("Operation baz completes at {0}", stopwatch.Elapsed);
    }
    Console.ReadKey();
}

else if (logTest == LogTest.Message)
{
    var random = new Random();
    var template = @"Method FoobarAsync is invoked.
    Arguments: foo={foo}, bar={bar}
    Return value: {returnValue}
    Time: {time}
";
    var log = LoggerMessage.Define<int, long, double, TimeSpan>(
        logLevel: LogLevel.Trace, eventId: 12356, formatString: template);
    var logger = new ServiceCollection()
        .AddLogging(builder => builder.SetMinimumLevel(LogLevel.Trace).AddConsole())
        .BuildServiceProvider()
        .GetRequiredService<ILoggerFactory>()
        .CreateLogger(typeof(Program).Namespace ?? "Program");

    await FoobarAsync(random.Next(), random.Next());
    await FoobarAsync(random.Next(), random.Next());
    Console.ReadKey();

    async Task<double> FoobarAsync(int foo, long bar)
    {
        var stopwatch = Stopwatch.StartNew();
        await Task.Delay(random.Next(100, 1000));
        var result = random.Next();
        log(logger, foo, bar, result, stopwatch.Elapsed, null);
        return result;
    }
}
else if (logTest == LogTest.Activity)
{
    var logger = new ServiceCollection()
        .AddLogging(builder => builder.Configure(options =>
                options.ActivityTrackingOptions = ActivityTrackingOptions.TraceId | ActivityTrackingOptions.SpanId |
                                                  ActivityTrackingOptions.ParentId)
            .AddConsole()
            .AddSimpleConsole(options => options.IncludeScopes = true))
        .BuildServiceProvider()
        .GetRequiredService<ILogger<Program>>();

    ActivitySource.AddActivityListener(new ActivityListener{ ShouldListenTo = _=> true, Sample = Sample});
    var source = new ActivitySource("Net06");
    using (source.StartActivity("Foo"))
    {
        logger.Log(LogLevel.Information, "This is a log for foo scope.");
        using (source.StartActivity("Bar"))
        {
            logger.Log(LogLevel.Information, "This is a log for bar scope.");
            using (source.StartActivity("Baz"))
            {
                logger.Log(LogLevel.Information, "This is a log for baz scope.");
            }
        }
    }

    Console.ReadKey();

    static ActivitySamplingResult Sample(ref ActivityCreationOptions<ActivityContext> options) =>
        ActivitySamplingResult.AllData;
}


enum LogTest
{
    JsonConfig,
    Simple,
    Message,
    Activity
}

